package net.chasing.androidbaseconfig.util;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.view.View;

import androidx.exifinterface.media.ExifInterface;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 上传图片的配置
 */
public class BitmapUtil {

    public static final int size = 700000;//图片宽*高不超过70w平方像素

    //获取图片尺寸,0为宽，1为高
    public static int[] getPhotoSize(Context context, String path) {
        int[] size = new int[2];
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            options.inPreferredConfig = Bitmap.Config.ALPHA_8;
            Bitmap bitmap = BitmapFactory.decodeStream(FileUtils.getInputStream(context, path), null, options);
            size[0] = options.outWidth;
            size[1] = options.outHeight;
            if (bitmap != null)
                bitmap.recycle();
        } catch (Exception ignored) {
        }
        return size;
    }

    public static Bitmap getBitmap(Context context, String path) throws IOException {
        //取得图片的流
        BufferedInputStream in = new BufferedInputStream(FileUtils.getInputStream(context, path));
        BitmapFactory.Options options = new BitmapFactory.Options();
        Bitmap bitmap = BitmapFactory.decodeStream(in, null, options);
        in.close();
        return bitmap;
    }

    public static Bitmap getBitmap(Context context, int resId) {
        return BitmapFactory.decodeResource(context.getResources(), resId, new BitmapFactory.Options());
    }

    //获取规定的宽度按比例缩放的Bitmap，可能会有几像素的偏差
    public static Bitmap getBitmapWithSize(Context context, String path, int w) {
        InputStream inputStream = FileUtils.getInputStream(context, path);
        if (inputStream == null) return null;
        int[] bitmapSize = getPhotoSize(context, path);
        Bitmap bitmap = null;
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream(inputStream);
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inScaled = true;
            options.inDensity = 1000;
            options.inTargetDensity = (int) (w / (float) bitmapSize[0] * options.inDensity);
            options.inJustDecodeBounds = false;
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            bitmap = BitmapFactory.decodeStream(in, null, options);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null)
                    in.close();
                inputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }

    //得到Bitmap，宽高积的最大像素不超过size（70w像素）
    public static Bitmap getBitmapInMaxSize(String path) throws IOException {
        //取得图片的流
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(path));
        BitmapFactory.Options options = new BitmapFactory.Options();
        //这个参数代表，不为bitmap分配内存空间，只记录一些该图片的信息（例如图片大小），说白了就是为了内存优化
        options.inJustDecodeBounds = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        //通过创建图片的方式，取得options的内容（这里就是利用了java的地址传递来赋值）
        BitmapFactory.decodeStream(in, null, options);
        in.close();
        //生成压缩的图片
        Bitmap bitmap;
        in = new BufferedInputStream(new FileInputStream(path));
        //这里之前设置为了true，所以要改为false，否则就创建不出图片
        options.inJustDecodeBounds = false;
        if (options.outHeight * options.outWidth > size) {
            //创建值
            double d = (double) size / (double) (options.outHeight * options.outWidth);
            options.inScaled = true;
            options.inDensity = 1000;
            options.inTargetDensity = (int) (Math.sqrt(d) * 1000);
            // will load & resize the image to be 1/inSampleSize dimensions
        }
        bitmap = BitmapFactory.decodeStream(in, null, options);
        in.close();
        return bitmap;
    }

    //获取规定比例的Bitmap
    public static Bitmap getBitmapWithScale(String path, int scale) {
        Bitmap bitmap = null;
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(path));
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = scale;
            options.inJustDecodeBounds = false;
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            bitmap = BitmapFactory.decodeStream(in, null, options);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }

    // 根据原图尺寸及需要的尺寸计算缩放比例
    private static int getCalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            int halfHeight = height / 2;
            int halfWidth = width / 2;
            while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    /**
     * 压缩图片并转换成输出流
     *
     * @param image 要压缩的图片
     * @param size  图片压缩尺寸，单位 kb
     */
    public static ByteArrayOutputStream getByteArrayOutputStream(Bitmap image, int size) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        image.compress(Bitmap.CompressFormat.WEBP, 80, baos);
        int options = 80;
        // 循环判断如果压缩后图片是否大于 size kb,大于继续压缩
        while (baos.toByteArray().length / 1024f > size && options > 10) {
            L.e("bitmapsize: " + baos.toByteArray().length);
            // 重置baos即清空baos
            baos.reset();
            // 每次都减少10
            options -= 10;
            // 这里压缩options%，把压缩后的数据存放到baos中
            image.compress(Bitmap.CompressFormat.WEBP, options, baos);
        }
        L.e("bitmapsize: " + baos.toByteArray().length);
        return baos;
    }

    // 将图片字节数组转换成缩放的bitmap
    public static Bitmap getCompressBitmap(Context context, byte[] bytes, int allowWidth, int allowHeight) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;//设置成了true,不占用内存，只获取bitmap宽高
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);

        opts.inPreferredConfig = Bitmap.Config.RGB_565;
        opts.inSampleSize = getCalculateInSampleSize(opts, allowWidth, allowHeight);
        opts.inScaled = true;

        double xSScale = ((double) opts.outWidth) / ((double) allowWidth);
        double ySScale = ((double) opts.outHeight) / ((double) allowHeight);

        double startScale = Math.max(xSScale, ySScale);
        // 小于1说明需要放大，则不进行
        if (startScale < 1)
            startScale = 1;
        int targetDensity = context.getResources().getDisplayMetrics().densityDpi;
        opts.inDensity = (int) (targetDensity * startScale);
        opts.inTargetDensity = targetDensity;
        opts.inJustDecodeBounds = false;//这里之前设置为了true，所以要改为false，否则就创建不出图片
        //Log.e("测试", "" + newBytes.length);
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
    }

    // 从resource资源获取缩放的bitmap
    public static Bitmap getCompressBitmapFromResource(Resources resources, int resId, int allowWidth, int allowHeight) {
        //循环压缩直到其大小小于32kb
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;//设置成了true,不占用内存，只获取bitmap宽高
        BitmapFactory.decodeResource(resources, resId, opts);
        opts.inPreferredConfig = Bitmap.Config.RGB_565;
        opts.inSampleSize = getCalculateInSampleSize(opts, allowWidth, allowHeight);
        opts.inScaled = true;

        double xSScale = ((double) opts.outWidth) / ((double) allowWidth);
        double ySScale = ((double) opts.outHeight) / ((double) allowHeight);

        double startScale = Math.max(xSScale, ySScale);
        int targetDensity = resources.getDisplayMetrics().densityDpi;
        opts.inDensity = (int) (targetDensity * startScale);
        opts.inTargetDensity = targetDensity;
        opts.inJustDecodeBounds = false;//这里之前设置为了true，所以要改为false，否则就创建不出图片
        //Log.e("测试", "" + newBytes.length);
        return BitmapFactory.decodeResource(resources, resId, opts);
    }

    // 对Bitmap进行缩放
    public static Bitmap getZoomImage(Bitmap bitmap, double maxSize) {
        if (null == bitmap) {
            return null;
        }
        if (bitmap.isRecycled()) {
            return null;
        }
        // 单位：从 Byte 换算成 KB
        double currentSize = bitmap.getByteCount() / 1024f;
        //double currentSize = bitmapToByteArray(bitmap, false).length / 1024;
        // 判断bitmap占用空间是否大于允许最大空间,如果大于则压缩,小于则不压缩
        while (currentSize > maxSize) {
            // 计算bitmap的大小是maxSize的多少倍
            double multiple = currentSize / maxSize;
            // 开始压缩：将宽带和高度压缩掉对应的平方根倍
            // 1.保持新的宽度和高度，与bitmap原来的宽高比率一致
            // 2.压缩后达到了最大大小对应的新bitmap，显示效果最好
            bitmap = getZoomImage(bitmap, bitmap.getWidth() / Math.sqrt(multiple), bitmap.getHeight() / Math.sqrt(multiple));
            //currentSize = bitmapToByteArray(bitmap, false).length / 1024;
            currentSize = bitmap.getByteCount() / 1024f;
        }
        return bitmap;
    }

    /**
     * 图片的缩放方法
     *
     * @param orgBitmap ：源图片资源
     * @param newWidth  ：缩放后宽度
     * @param newHeight ：缩放后高度
     */
    private static Bitmap getZoomImage(Bitmap orgBitmap, double newWidth, double newHeight) {
        if (null == orgBitmap) {
            return null;
        }
        if (orgBitmap.isRecycled()) {
            return null;
        }
        if (newWidth <= 0 || newHeight <= 0) {
            return null;
        }

        // 获取图片的宽和高
        float width = orgBitmap.getWidth();
        float height = orgBitmap.getHeight();
        // 创建操作图片的matrix对象
        Matrix matrix = new Matrix();
        // 计算宽高缩放率
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 缩放图片动作
        matrix.postScale(scaleWidth, scaleHeight);
        return Bitmap.createBitmap(orgBitmap, 0, 0, (int) width, (int) height, matrix, true);
    }

    /**
     * 读取照片旋转角度
     *
     * @param path 照片路径
     * @return 角度
     */
    public static int readPictureDegree(Context context, String path) {
        InputStream inputStream = FileUtils.getInputStream(context, path);
        if (inputStream == null) return 0;
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(inputStream);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    //按图片原尺寸进行旋转角度
    public static Bitmap rotate(Bitmap bm, int degree) {
        Matrix matrix = new Matrix();
        matrix.postScale(1.0f, 1.0f);
        matrix.setRotate(degree);
        return Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
    }

    /**
     * view转bitmap
     * 仅限在视图上能看到的View
     */
    public static Bitmap viewConversionBitmapWithScale(View v) {
        int w = v.getWidth();
        int h = v.getHeight();
        if (w == 0) {
            int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            v.measure(size, size);
            w = v.getMeasuredWidth();
            h = v.getMeasuredHeight();
        }
        Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bmp);
        // 如果不设置canvas画布为白色，则生成透明
        c.drawColor(Color.WHITE);
        v.layout(0, 0, w, h);
        v.draw(c);
        c.scale(400 / (float) w, 180 / (float) h);

        return bmp;
    }

    public static Bitmap viewConversionBitmap(View v) {
        int w = v.getWidth();
        int h = v.getHeight();
        if (w == 0) {
            int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            v.measure(size, size);
            w = v.getMeasuredWidth();
            h = v.getMeasuredHeight();
        }
        Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bmp);
        v.layout(0, 0, w, h);
        v.draw(c);
        return bmp;
    }

    public static byte[] bitmapToByte(Bitmap bmp, int quality) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.WEBP, quality, baos);
        try {
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static Bitmap compressBitmap(Bitmap bmp, int quality) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.WEBP, quality, baos);
        try {
            byte[] bytes = baos.toByteArray();
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bmp;
    }

    // 图片缩放比例(即模糊度)
    private static final float BITMAP_SCALE = 0.4f;

    /**
     * @param context    上下文对象
     * @param image      需要模糊的图片
     * @param blurRadius 设置渲染的模糊程度, Supported range 0 < radius <= 25
     * @return 模糊处理后的Bitmap
     */
    public static Bitmap blurBitmap(Context context, Bitmap image, float blurRadius) {
        // 计算图片缩小后的长宽
        int width = Math.round(image.getWidth() * BITMAP_SCALE);
        int height = Math.round(image.getHeight() * BITMAP_SCALE);

        // 将缩小后的图片做为预渲染的图片
        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
        // 创建一张渲染后的输出图片
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);

        // 创建RenderScript内核对象
        RenderScript rs = RenderScript.create(context);
        // 创建一个模糊效果的RenderScript的工具对象
        ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

        // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间
        // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去
        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);

        // 设置渲染的模糊程度, Supported range 0 < radius <= 25
        blurScript.setRadius(blurRadius);
        // 设置blurScript对象的输入内存
        blurScript.setInput(tmpIn);
        // 将输出数据保存到输出内存中
        blurScript.forEach(tmpOut);

        // 将数据填充到Allocation中
        tmpOut.copyTo(outputBitmap);

        return outputBitmap;
    }
}
